package com.stylefeng.guns.modular.assessment.controller;

import com.github.abel533.echarts.Option;
import com.github.abel533.echarts.axis.CategoryAxis;
import com.github.abel533.echarts.axis.ValueAxis;
import com.github.abel533.echarts.code.Tool;
import com.github.abel533.echarts.code.Trigger;
import com.github.abel533.echarts.code.X;
import com.github.abel533.echarts.json.GsonOption;
import com.github.abel533.echarts.series.Line;
import com.stylefeng.guns.common.constant.factory.ConstantFactory;
import com.stylefeng.guns.common.exception.BussinessException;
import com.stylefeng.guns.common.persistence.model.Assessment;
import com.stylefeng.guns.common.plugin.entity.Period;
import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.core.log.LogObjectHolder;
import com.stylefeng.guns.core.support.BeanKit;
import com.stylefeng.guns.core.support.CollectionKit;
import com.stylefeng.guns.core.support.DateTimeKit;
import com.stylefeng.guns.modular.assessment.AssessmentWrapper;
import com.stylefeng.guns.modular.assessment.service.IAssessmentService;
import com.vip.vjtools.vjkit.time.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.*;

import static com.stylefeng.guns.common.exception.BizExceptionEnum.REQUEST_INVALIDATE;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

/**
 * 指标评估控制器
 *
 * @author xuziyang
 * @Date 2018-03-27 16:50:19
 */
@Controller
@RequestMapping("/assessment")
public class AssessmentController extends BaseController {

	private String PREFIX = "/assessment/";

	@Autowired
	private IAssessmentService assessmentService;

	/**
	 * 跳转到指标评估首页
	 */
	@RequestMapping("")
	public String index() {
		return PREFIX + "assessment.html";
	}

	/**
	 * 预警
	 *
	 * @return
	 */
	@RequestMapping("warning")
	public String warning() {
		return PREFIX + "warning.html";
	}

	@RequestMapping("warning_info")
	public String warningInfo(@RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") Date beginDate) {
		
		return PREFIX + "warning.html";
	}

	@RequestMapping("assessment_char")
	public String toChar() {
		return PREFIX + "assessment_char.html";
	}

	/**
	 * 跳转到添加指标评估
	 */
	@RequestMapping("/assessment_add")
	public String assessmentAdd() {
		return PREFIX + "assessment_add.html";
	}

	/**
	 * 跳转到修改指标评估
	 */
	@RequestMapping("/assessment_update/{assessmentId}")
	public String assessmentUpdate(@PathVariable Integer assessmentId, Model model) {
		Assessment assessment = assessmentService.selectById(assessmentId);
		model.addAttribute("item", assessment);
		LogObjectHolder.me().set(assessment);
		return PREFIX + "assessment_edit.html";
	}

	/**
	 * 获取指标评估列表
	 */
	@RequestMapping(value = "/list")
	@ResponseBody
	public List<Map<String, Object>> list(
			@RequestParam(value = "beginDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date beginDate,
			@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
			@RequestParam(value = "roadnetId", required = false) Integer roadnetId) {

		if (beginDate == null || endDate == null || roadnetId == null) {
			return null;
		}

		if (!validRequestParams(beginDate, endDate, roadnetId)) {
			throw new BussinessException(REQUEST_INVALIDATE);
		}

		List<Period> periodList = getPeriodList(beginDate, endDate);
		List<Assessment> firstAssessmentList = assessmentService.assessmentMulPeriod(roadnetId, periodList);
		List<Map<String, Object>> mapList = assessmentFlatToMap(firstAssessmentList);
		return (List<Map<String, Object>>) new AssessmentWrapper(mapList).warp();
	}


	@RequestMapping("line")
	@ResponseBody
	public Object line(
			@RequestParam(value = "beginDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date beginDate,
			@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
			@RequestParam(value = "roadnetId", required = false) Integer roadnetId) {

		if (!validRequestParams(beginDate, endDate, roadnetId)) {
			throw new BussinessException(REQUEST_INVALIDATE);
		}

		List<Period> dateList = getPeriodList(beginDate, endDate);

		List<Assessment> firstAssessmentList = assessmentService.assessmentMulPeriod(roadnetId, dateList);
		firstAssessmentList.sort(Comparator.comparing(Assessment::getBeginTime));

		List<Assessment> secondAssessmentList = firstAssessmentList.stream().map(Assessment::getNexLvlList)
				.flatMap(List::stream).collect(toList());
		List<Assessment> thirdAssessmentList = secondAssessmentList.stream().map(Assessment::getNexLvlList)
				.flatMap(List::stream).collect(toList());

		Map<Integer, List<Assessment>> secondAssessmentMapByIndicaiton = secondAssessmentList.stream()
				.collect(groupingBy(Assessment::getIndicationId));

		Map<Integer, List<Assessment>> thirdAssessmentMapByIndication = thirdAssessmentList.stream()
				.collect(groupingBy(Assessment::getIndicationId));

		String firstOption = toOption(firstAssessmentList);
		List<String> secondOptionList = secondAssessmentMapByIndicaiton.values().stream().map(this::toOption)
				.collect(toList());
		List<String> thirdOptionList = thirdAssessmentMapByIndication.values().stream().map(this::toOption)
				.collect(toList());

		Map<Integer, List<String>> map = new HashMap<>();
		map.put(1, Arrays.asList(firstOption));
		map.put(2, secondOptionList);
		map.put(3, thirdOptionList);

		return map;
	}

	private String toOption(List<Assessment> assessmentList) {
		Integer indicationId = assessmentList.get(0).getIndicationId();
		String indicationName = ConstantFactory.me().getIndicationNameById(indicationId);

		List<String> xList = assessmentList.stream().map(Assessment::getBeginTime).map(this::getDateStr)
				.collect(toList());

		List<Double> yList = assessmentList.stream().map(Assessment::getAssessmentValue).collect(toList());


		Option option = new GsonOption();
		option.title().text(indicationName).x(X.center);


		option.legend().x(X.left).data(indicationName);

		option.toolbox().show(true)
				.feature(Tool.saveAsImage);
		option.tooltip().trigger(Trigger.item).formatter("{a} <br/>{b} : {c}");
		option.calculable(true);

		option.yAxis(new ValueAxis().name("风险值"));


		CategoryAxis categoryAxis = new CategoryAxis();
		categoryAxis.name("时间").splitLine().show(false);
		categoryAxis.setData(xList);

		option.xAxis(categoryAxis);

		ValueAxis valueAxis = new ValueAxis();
		valueAxis.axisLabel().formatter("{value}");
		option.xAxis(valueAxis);

		Line line = new Line(indicationName);
		line.setData(yList);

		option.series(line);
		return option.toString();
	}

	private String getDateStr(Date date) {
		return DateTimeKit.format(date, "yy-MM-dd");
	}


	private void setWarningLevelName(Assessment assessment, Map<String, Object> map) {
		int warningLevel = assessment.getWarningLevel();
		String warningLevelName = null;
		if (warningLevel == 0) {
			warningLevelName = "正常";
		} else if (warningLevel == Assessment.WARNING_LEVEL_LOW) {
			warningLevelName = "低风险";
		} else if (warningLevel == Assessment.WARNING_LEVEL_LOWER) {
			warningLevelName = "较低风险";
		} else if (warningLevel == Assessment.WARNING_LEVEL_MEDIUM) {
			warningLevelName = "中风险";
		} else if (warningLevel == Assessment.WARNING_LEVEL_HIGH) {
			warningLevelName = "高风险";
		} else {
			warningLevelName = "异常";
		}
		map.put("warningLevelName", warningLevelName);
	}

	private List<Map<String, Object>> assessmentFlatToMap(List<Assessment> firstIndicationAssessmentList) {
		List<Map<String, Object>> mapList = new ArrayList<>();
		firstIndicationAssessmentList.stream().forEach(assessment -> assessmentRecursionToMap(mapList, assessment, "0"));
		return mapList;
	}

	private void assessmentRecursionToMap(List<Map<String, Object>> acc, Assessment assessment, String pid) {
		assessment.setTreeCode(UUID.randomUUID().toString());
		if (assessment == null)
			return;
		if (CollectionKit.isNotEmpty(assessment.getNexLvlList()))
			assessment.getNexLvlList().stream().forEach(
					nexAssessment -> assessmentRecursionToMap(acc, nexAssessment, assessment.getTreeCode()));
		Map<String, Object> map = BeanKit.beanToMap(assessment);
		map.remove("nexLvlList");
		map.put("pid", pid);
		setWarningLevelName(assessment, map);
		acc.add(map);
	}

	private List<Period> getPeriodList(Date beginDate, Date endDate) {
		List<Period> dateList = new ArrayList<>();

		Date currentDate = beginDate;
		do {
			Period period = new Period();
			period.setBeginDate(currentDate);
			period.setEndDate(new Date(DateUtil.nextDate(currentDate).getTime() - 1000));
			dateList.add(period);
			currentDate = DateUtil.nextDate(currentDate);
		} while (currentDate.compareTo(endDate) <= 0);
		return dateList;
	}


	private boolean validRequestParams(Date beginDate, Date endDate, Integer roadnetId) {
		if (roadnetId == null || beginDate == null || endDate == null) {
			return false;
		}
		//结束日期大于开始日期
		if (endDate.compareTo(beginDate) == -1) {
			return false;
		}

		return true;
	}

}
